////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camximagebuffermanager.h
///
/// @brief Camera image buffer manager definition
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CAMXIMAGEBUFFERMANAGER_H
#define CAMXIMAGEBUFFERMANAGER_H

#include "camximagebuffer.h"
#include "camxlist.h"
#include "camxosutils.h"
#include "camxthreadmanager.h"
#include "camxtypes.h"

CAMX_NAMESPACE_BEGIN

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Forward Declarations
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ImageBufferManager;
class ImageBuffer;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Type definitions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Define the arguments to be supplied for allocating image buffers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ImageBufferManagerThreadData
{
    ImageBufferManager*   pImageBufferManager;   ///< Instance pointer of the class
    ImageBuffer*          pImageBuffer;          ///< Pointer to the image buffer
    ImageFormat           imageFormat;           ///< Pointer to the image format of the buffers to be managed
    UINT32                flags;                 ///< Usage flags for indicating to the KMD how buffer will be used for proper
                                                 ///< allocation and mapping
    INT32*                pDeviceIndices;        ///< Pointer to array of device indices that may access this buffer
    UINT                  deviceCount;           ///< The number of valid entries in the array pointed to by pDeviceIndices
    BOOL                  allocateBufferMemory;  ///< Boolean indicating whether buffer memory should be allocated
    UINT                  numBatchedFrames;      ///< Number of frames batched together
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief The ImageBufferManager manages a pool of homogeneous frame buffers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class ImageBufferManager
{
public:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Create
    ///
    /// @brief  Create a new image buffer manager.
    ///
    /// @param  pBufferManagerName   Name of the image buffer manager.
    /// @param  ppImageBufferManager Newly created image buffer manager.
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static CamxResult Create(
        const CHAR*          pBufferManagerName,
        ImageBufferManager** ppImageBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Destroy
    ///
    /// @brief  Destroy this image buffer manager.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Destroy();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeBuffers
    ///
    /// @brief  Initialize image buffers for a given format and queue in the buffer manager.
    ///
    /// @param  pFormat               The image format of the buffers to be managed. The buffer manager will not retain any
    ///                               reference to this pointer after the return of the constructor.
    /// @param  maxBufferCount        The maximum number of buffers to allocate.
    /// @param  immediateBufferCount  The number of buffers to be allocated immediately
    /// @param  flags                 Usage flags indicating to KMD how buffer will be used for proper allocation and mapping.
    /// @param  pDeviceIndices        Pointer to array of device indices that may access this buffer.
    /// @param  deviceCount           The number of valid entries in the array pointed to by pDeviceIndices.
    /// @param  allocateBufferMemory  Boolean indicating whether buffer memory should be allocated.
    /// @param  numBatchedFrames      Number of frames batched together
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult InitializeBuffers(
        const ImageFormat* pFormat,
        UINT               maxBufferCount,
        UINT               immediateBufferCount,
        UINT32             flags,
        const INT32*       pDeviceIndices,
        UINT               deviceCount,
        BOOL               allocateBufferMemory,
        UINT               numBatchedFrames);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetImageBuffer
    ///
    /// @brief  Retrieve an available buffer from the buffer pool. Buffers are retrieved in FIFO order.
    ///
    /// @return Pointer to an ImageBuffer. If buffers are not allocated, not available, or some other error, NULL is returned.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ImageBuffer* GetImageBuffer();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ReleaseBuffers
    ///
    /// @brief  Release any buffers allocated by the buffer manager.
    ///
    /// @param  isPartialRelease   If TRUE, release buffers until m_immediateAllocBufferCount is reached; else release all
    ///
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ReleaseBuffers(
        BOOL isPartialRelease);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddReference
    ///
    /// @brief  Add reference to the image buffer
    ///
    /// @param  pImageBuffer   Image buffer object
    ///
    /// @return The reference count of the ImageBuffer after adding reference
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT AddReference(
        ImageBuffer* pImageBuffer);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ReleaseReference
    ///
    /// @brief  Release reference to the image buffer
    ///
    /// @param  pImageBuffer   Image buffer object
    ///
    /// @return The reference count of the ImageBuffer after releasing
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT ReleaseReference(
        ImageBuffer* pImageBuffer);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetBufferManagerName
    ///
    /// @brief  Return the buffer manager's name
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CHAR* GetBufferManagerName();

private:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ImageBufferManager
    ///
    /// @brief  Create a new buffer manager instance. The buffer manager does not contain any buffers when initialized.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ImageBufferManager();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ~ImageBufferManager
    ///
    /// @brief  The destructor. Destructing a buffer manager with buffers will be release them. The client should take care to
    ///         ensure there are no outstanding references to buffers when the buffer manager is destroyed.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ~ImageBufferManager();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Initialize
    ///
    /// @brief  Initialize the buffer manager. This method must be called before any other methods after construction.
    ///
    /// @param  pBufferManagerName   Name of the image buffer manager.
    ///
    /// @return CamxResultSuccess if successful.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Initialize(
        const CHAR* pBufferManagerName);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FreeBuffers
    ///
    /// @brief  Free all image buffers (if any) including backing memory.
    ///
    /// @param  isPartialRelease   If TRUE, release buffers until m_immediateAllocBufferCount is reached; else release all
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID FreeBuffers(
        BOOL isPartialRelease);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FreeResources
    ///
    /// @brief  Free all internal resources allocated by the ImageBufferManager.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID FreeResources();

    ImageBufferManager(const ImageBufferManager& other)            = delete;
    ImageBufferManager& operator=(const ImageBufferManager& other) = delete;

    CHAR           m_pBufferManagerName[MaxStringLength64]; ///< Name of the buffer manager
    UINT           m_immediateAllocBufferCount;             ///< Initial number of buffers to be allocated
    UINT           m_maxBufferCount;                        ///< Maximum number of buffers to be allocated
    Mutex*         m_pLock;                                 ///< Mutex to protect buffer manager internal state.
    Condition*     m_pWaitFreeBuffer;                       ///< Wait till free buffers are available in the buffer manager

    ImageBufferManagerThreadData m_threadData;              ///< Data structure to be passed as argument to the thread callback
    LightweightDoublyLinkedList  m_freeBufferList;          ///< Free list of buffers which are available for use at any time.
    LightweightDoublyLinkedList  m_busyBufferList;          ///< List of buffers given to the client.
};

CAMX_NAMESPACE_END

#endif // CAMXIMAGEBUFFERMANAGER_H
